#include <iostream>
#include <conio.h>
#include <direct.h>
#include <string>

#include <WinSock2.h>
#include <Ws2tcpip.h>
#include <Windows.h>
#pragma comment (lib, "ws2_32.lib")
using namespace std;

class MyGitNet
{
public:
	MyGitNet(const char* addr, u_short post)
	{
		listening = false;
		netsock = socket(AF_INET, SOCK_STREAM, 0);
		if (netsock == SOCKET_ERROR)
		{
			throw WSAGetLastError();
		}

		netaddr.sin_family = AF_INET;
		netaddr.sin_port = htons(post);
		if (inet_pton(AF_INET, addr, &netaddr.sin_addr) != 1)
		{
			throw WSAGetLastError();
		}

		if (::bind(netsock, (LPSOCKADDR)&netaddr, sizeof(netaddr)) == SOCKET_ERROR)
		{
			throw WSAGetLastError();
		}
	}

	void SetListen(int backlog)
	{
		if (listen(netsock, backlog) == SOCKET_ERROR)
		{
			throw WSAGetLastError();
		}
		listening = true;
	}

	void Accept()
	{
		int size = sizeof(netaddr2);
		netsock2 = accept(netsock, (LPSOCKADDR)&netaddr2, &size);
		if (netsock2 == SOCKET_ERROR)
		{
			throw WSAGetLastError();
		}
	}

	void Connect()
	{
		if (connect(netsock, (LPSOCKADDR)&netaddr, sizeof(netaddr)))
		{
			throw WSAGetLastError();
		}
	}

	bool Send(void* buf, size_t size, int waittime = 20000)
	{
		size_t rs;
		setsockopt((listening) ? netsock2 : netsock, SOL_SOCKET, SO_RCVTIMEO, (char*)&waittime, sizeof(waittime));
		setsockopt((listening) ? netsock2 : netsock, SOL_SOCKET, SO_SNDTIMEO, (char*)&waittime, sizeof(waittime));
		if (send((listening) ? netsock2 : netsock, (char*)&size, sizeof(size), 0) <= 0) { return false; }

		bool success = false;
		if (send((listening) ? netsock2 : netsock, (char*)buf, size, 0) <= 0) { return false; }

		if (recv((listening) ? netsock2 : netsock, (char*)&success, sizeof(success), MSG_WAITALL) <= 0) { return false; }
		if (!success) { return false; }
		return true;
	}

	bool Recv(void* buf, int waittime = 20000)
	{
		setsockopt((listening) ? netsock2 : netsock, SOL_SOCKET, SO_RCVTIMEO, (char*)&waittime, sizeof(waittime));
		setsockopt((listening) ? netsock2 : netsock, SOL_SOCKET, SO_SNDTIMEO, (char*)&waittime, sizeof(waittime));
		size_t resize;
		if (recv((listening) ? netsock2 : netsock, (char*)&resize, sizeof(resize), MSG_WAITALL) <= 0) { return false; }
		buf = new unsigned char[resize];
		if (recv((listening) ? netsock2 : netsock, (char*)buf, resize, MSG_WAITALL) <= 0) { delete[] buf; return false; }
		const bool success = true;
		if (send((listening) ? netsock2 : netsock, (char*)&success, sizeof(success), 0) <= 0) {}

		return true;
	}

	static bool IsInit()
	{
		return init;
	}

	static bool InitNet()
	{
		WSADATA version_data;
		if (WSAStartup(MAKEWORD(2, 2), &version_data) != 0)
		{
			return init;
		}
		else
		{
			init = true;
			return init;
		}
	}

protected:
	bool listening;
	static bool init;
	SOCKET netsock;
	SOCKET netsock2;
	sockaddr_in netaddr;
	sockaddr_in netaddr2;
};

bool MyGitNet::init = false;

int main()
{
	if (!MyGitNet::IsInit())
	{
		MyGitNet::InitNet();
	}

	

	return 0;
}